创建多人React游戏时未定义上下文

时间:2018-07-11 15:01:53

标签: reactjs sockets canvas redux

尊敬的StackOverflow员工

我正在创建一个多人游戏。我添加了一个画布,但是在eveytime时,我将组件连接到商店时出现错误:上下文未定义。我必须连接到商店的原因是为了获得更新逻辑的游戏道具。如果我不尝试游戏道具,那么就没有道具状态,代码就可以正常工作。这是中断的代码:

class Ship extends GameObject {
  constructor(args) {
    super({
      position: args.position,
      onDie: args.onDie,
      speed: 2.5,
      radius: 15
    });


    this.bullets = [];
    this.lastShot = 0;

  }

  componentWillMount() {
    if (this.props.authenticated) {
      if (this.props.game === null) this.props.getGames()
      if (this.props.users === null) this.props.getUsers()
    }
  }

  update(keys) {
    const {
      game,
      users,
      authenticated,
      userId
    } = this.props
    const player = game.players.find(p => p.userId === userId)
    const player1 = player.ship
    if (player1 === 'shipa') {
      if (keys.right) {
        this.position.x += this.speed;
      } else if (keys.left) {
        this.position.x -= this.speed;
      } else if (keys.up) {
        this.position.y -= this.speed;
      } else if (keys.down) {
        this.position.y += this.speed;
      }

      if (keys.space && Date.now() - this.lastShot > 250) {
        const bullet = new Bullet({
          position: {
            x: this.position.x,
            y: this.position.y - 5
          },
          direction: "up"
        });

        this.bullets.push(bullet);
        this.lastShot = Date.now();
      }
    }
  }

  renderBullets(state) {
    let index = 0;
    for (let bullet of this.bullets) {
      if (bullet.delete) {
        this.bullets.splice(index, 1);
      } else {
        this.bullets[index].update();
        this.bullets[index].render(state);
      }
      index++;
    }
  }

  render(state) {
    if (this.position.x > state.screen.width) {
      this.position.x = 0;
    } else if (this.position.x < 0) {
      this.position.x = state.screen.width;
    }
    if (this.position.y > state.screen.height) {
      this.position.y = 0;
    } else if (this.position.y < 0) {
      this.position.y = state.screen.height;
    }

    this.renderBullets(state);

    const context = state.context;
    context.save();
    context.translate(this.position.x, this.position.y);
    context.strokeStyle = '#ffffff';
    context.fillStyle = '#ffffff';
    context.lineWidth = 2;
    context.beginPath();
    context.moveTo(0, -25);
    context.lineTo(15, 15);
    context.lineTo(5, 7);
    context.lineTo(-5, 7);
    context.lineTo(-15, 15);
    context.closePath();
    context.fill();
    context.stroke();
    context.restore();
  }
}
const mapStateToProps = (state, props) => ({
  authenticated: state.currentUser !== null,
  userId: state.currentUser && userId(state.currentUser.jwt),
  game: state.games && state.games[props.match.params.id],
  users: state.users
})

const mapDispatchToProps = {
  getGames,
  getUsers,
  joinGame,
  updateGame
}

export default connect(mapStateToProps, mapDispatchToProps)(Ship)

游戏对象:

export default class GameObject {
    constructor(args){
        this.position = args.position;
        this.onDie = args.onDie;
        this.speed = args.speed;
        this.radius = args.radius;
        this.delete = false;
    }

    die() {
        this.delete = true;
        if (this.onDie) {
            this.onDie();
        }
    }

    render(state) {
        if(this.position.x > state.screen.width) {
            this.position.x = 0;
        }
        else if(this.position.x < 0) {
            this.position.x = state.screen.width;
        }
        if(this.position.y > state.screen.height) {
            this.position.y = 0;
        }
        else if(this.position.y < 0) {
            this.position.y = state.screen.height;
        }
    }
}

这是上下文来自哪里:

import React, { Component } from 'react';
import InputManager from './InputManager';
import TitleScreen from './TitleScreen';
import GameOverScreen from './GameOverScreen';
import ControlOverlay from './ControlOverlay';
import Ship from './Ship';
import Ship2 from './Ship2';
import Invader from './Invader';
import { checkCollisionsWith, checkCollision } from './Helper';

import {connect} from 'react-redux'
import {Redirect} from 'react-router-dom'
import {getGames, joinGame, updateGame} from '../../actions/games'
import {getUsers} from '../../actions/users'
import {userId} from '../../jwt'


const width = 800;
const height = window.innerHeight;

const GameState = {
   StartScreen : 0,
   Playing : 1,
   GameOver : 2
};

class Canvas extends Component {
  constructor() {
    super();
    this.state = {
      input: new InputManager(),
      screen: {
        width: width,
        height: height,
        ratio: window.devicePixelRatio || 1
      },
      score: 0,
      gameState: GameState.StartScreen,
      previousState: GameState.StartScreen,
      context: null
    };

    this.ship = null;
    this.ship2 = null;
    this.invaders = [];
    this.lastStateChange = 0;
    this.previousDelta = 0;
    this.fpsLimit = 30;
    this.showControls = false;
  }

  componentWillMount() {
    if (this.props.authenticated) {
      if (this.props.game === null) this.props.getGames()
      if (this.props.users === null) this.props.getUsers()
    }
  }

  joinGame = () => this.props.joinGame(this.props.game.id)

  handleResize(value, e){
    this.setState({
      screen : {
        width: width,
        height: height,
        ratio: window.devicePixelRatio || 1,
      }
    });
  }

  startGame() {
    let ship = new Ship({
      onDie: this.die.bind(this),
      position: {
        x: this.state.screen.width/2,
        y: this.state.screen.height - 50
      }});
    this.ship = ship;

    let ship2 = new Ship2({
      onDie: this.die.bind(this),
      position: {
        x: this.state.screen.width/3,
        y: this.state.screen.height - 50
      }});
    this.ship2 = ship2;

    this.createInvaders(27);

    this.setState({
      gameState: GameState.Playing,
      score: 0
    });
    this.showControls = true;
  }

  die() {
    this.setState({ gameState: GameState.GameOver });
    this.ship = null;
    this.ship2 = null;
    this.invaders = [];
    this.lastStateChange = Date.now();
  }

  increaseScore(val) {
    this.setState({ score: this.state.score + 500 });
  }

  update(currentDelta) {
    var delta = currentDelta - this.previousDelta;

    if (this.fpsLimit && delta < 1000 / this.fpsLimit) {
      return;
    }

    const keys = this.state.input.pressedKeys;
    const context = this.state.context;

    if (this.state.gameState === GameState.StartScreen && keys.enter && Date.now() - this.lastStateChange > 2000) {
      this.startGame();
    }

    if (this.state.gameState === GameState.GameOver && keys.enter) {
      this.setState({ gameState: GameState.StartScreen});
    }

    if (this.state.gameState === GameState.Playing && Date.now() - this.lastStateChange > 500) {
      if (this.state.previousState !== GameState.Playing) {
        this.lastStateChange = Date.now();
      }

      if (this.invaders.length === 0) {
        this.setState({ gameState: GameState.GameOver });
      }

      context.save();
      context.scale(this.state.screen.ratio, this.state.screen.ratio);

      context.fillRect(0, 0, this.state.screen.width, this.state.screen.height);
      context.globalAlpha = 1;
      checkCollisionsWith(this.ship.bullets, this.invaders);
      checkCollisionsWith([this.ship], this.invaders);

      if (keys.space || keys.left || keys.right) {
        this.showControls = false;
      }

      for (var i = 0; i < this.invaders.length; i++) {
        checkCollisionsWith(this.invaders[i].bullets, [this.ship]);
      }

      if (this.ship !== null) {
        this.ship.update(keys);
        this.ship.render(this.state);
      }

      if (this.ship2 !== null) {
        this.ship2.update(keys);
        this.ship2.render(this.state);
      }

      this.renderInvaders(this.state);
      this.setState({previousState: this.state.gameState});
      context.restore();
    }

    requestAnimationFrame(() => {this.update()});
  }

  createInvaders(count) {
    const newPosition = { x: 100, y: 20 };
    let swapStartX = true;

    for (var i = 0; i < count; i++) {
      const invader = new Invader({
         position: { x: newPosition.x, y: newPosition.y },
         onDie: this.increaseScore.bind(this, false)
      });

      newPosition.x += invader.radius + 20;

      if (newPosition.x + invader.radius + 50 >= this.state.screen.width) {
        newPosition.x = swapStartX ? 110 : 100;
        swapStartX = !swapStartX;
        newPosition.y += invader.radius + 20;
      }

      this.invaders.push(invader);
    }
  }

  renderInvaders(state) {
    let index = 0;
    let reverse = false;

    for (let invader of this.invaders) {
      if (invader.delete) {
        this.invaders.splice(index, 1);
      }
      else if (invader.position.x + invader.radius >= this.state.screen.width ||
               invader.position.x - invader.radius <= 0) {
        reverse = true;
      }
      else {
        this.invaders[index].update();
        this.invaders[index].render(state);
      }
      index++;
    }

    if (reverse) {
      this.reverseInvaders();
    }
  }

  reverseInvaders() {
    let index = 0;
    for (let invader of this.invaders) {
      this.invaders[index].reverse();
      this.invaders[index].position.y += 50;
      index++;
    }
  }

  componentDidMount() {
    window.addEventListener('resize',  this.handleResize.bind(this, false));
    this.state.input.bindKeys();
    const context = this.refs.canvas.getContext('2d');
    this.setState({ context: context });

    requestAnimationFrame(() => {this.update()});
  }

  componentWillUnmount() {
    this.state.input.unbindKeys();
    window.removeEventListener('resize', this.handleResize);
  }

  render() {
    const {game, users, authenticated, userId} = this.props

    if (!authenticated) return (
            <Redirect to="/login" />
        )

    if (game === null || users === null) return 'Loading...'
    if (!game) return 'Not found'

    const player = game.players.find(p => p.userId === userId)

    return (
      <div>

        {
          game.status === 'pending' &&
          game.players.map(p => p.userId).indexOf(userId) === -1 &&
          <button onClick={this.joinGame}>Join Game</button>
        }

        { this.showControls && <ControlOverlay /> }
        { this.state.gameState === GameState.StartScreen && <TitleScreen /> }
        { this.state.gameState === GameState.GameOver && <GameOverScreen score= { this.state.score } /> }
        <canvas ref="canvas"
           width={ this.state.screen.width * this.state.screen.ratio }
           height={ this.state.screen.height * this.state.screen.ratio }
        />
      </div>
    );
  }
}
const mapStateToProps = (state, props) => ({
  authenticated: state.currentUser !== null,
  userId: state.currentUser && userId(state.currentUser.jwt),
  game: state.games && state.games[props.match.params.id],
  users: state.users
})

const mapDispatchToProps = {
  getGames, getUsers, joinGame, updateGame
}

export default connect(mapStateToProps, mapDispatchToProps)(Canvas)
// export default Canvas;

0 个答案:

没有答案