7.1.2_抛射体弹道运动_小球投掷游戏
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>抛射体弹道运动——小球投掷游戏</title>
<style>
output{
color:blue;
}
.floatingControls{
background: rgba(0,0,0,0.1);
border: thin solid skyblue;
box-shadow: rgba(100,140,230,0.5) 2px 2px 6px;
-moz-box-shadow: rgba(100,140,230,0.5) 2px 2px 6px;
-webkit-box-shadow: rgba(100,140,230,0.5) 2px 2px 6px;
padding: 15px;
font: 12px arial;
}
#canvas{
background: skyblue;
box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
-moz-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
-webkit-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
cursor: pointer;
}
#scoreBoard{
background: rgba(255,255,255,0.5);
position: absolute;
left: 755px;
top: 20px;
color: blue;
font-size: 18px;
padding: 5px;
}
#controls{
position: absolute;
left: 285px;
top: 20px;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="450"></canvas>
<div id="scoreBoard" class="floatingControls">0</div>
<div id="controls" class="floatingControls">
发射速度(m/s):<output id="launchVelocityOutput"></output>m/s<br>
发射角度(deg):<output id="launchAngleOutput"></output>degs<br />
</div>
</body>
<script>
var Sprite = function(name,painter,behaviors){
if(name !== undefined){ this.name = name; }
if(painter !== undefined){ this.painter = painter; }
this.top = 0;
this.left = 0;
this.width = 10;
this.height = 10;
this.velocityX = 0;
this.velocityY = 0;
this.visible = true;
this.animating = false;
this.behaviors = behaviors || [];
}
Sprite.prototype = {
paint:function(context){
if(this.painter !== undefined && this.visible){
this.painter.paint(this,context);
}
},
update:function(context,time){
for(var i=0;i<this.behaviors.length;i++){
this.behaviors[i].execute(this,context,time);
}
}
}
</script>
<script>
var ImagePainter = function (imageUrl){
this.image = new Image();
this.image.src = imageUrl;
}
ImagePainter.prototype ={
paint:function(sprite,context){
if(this.image.complete){
context.drawImage(this.image,sprite.left,sprite.top,sprite.width,sprite.height);
}
}
}
</script>
<script>
var canvas =document.getElementById('canvas'),
context = canvas.getContext('2d'),
scoreBoard = document.getElementById('scoreBoard'),
launchAngleOutput = document.getElementById('launchAngleOutput'),
launchVelocityOutput = document.getElementById('launchVelocityOutput'),
elapsedTime = undefined,
launchTime = undefined,
score = 0,
lastScore = 0,
lastMouse = {left:0,top:0},
threePointer = false,
needInstructions = true,
launchPad_x =50,
launchPad_y = context.canvas.height - 50,
launch_width = 50,
launch_height = 12,
ball_radius = 8,
arena_length_in_meters = 10,
initial_launch_angle = Math.PI/4,
launchAngle = initial_launch_angle,
launchVelocity = 0,
pixelsPerMeter = canvas.width/arena_length_in_meters,
ballInFlight = false,
bucket_x = 668,
bucket_y = canvas.height -100,
bucket_width = 50,
bucket_height = 54,
launchPadPainter = {
launchpad_fill_style : 'rgb(100,140,230)',
paint:function(sprite,context){
context.save();
context.fillStyle = this.launchpad_fill_style;
context.fillRect(launchPad_x,launchPad_y,launch_width,launch_height);
context.restore();
}
},
launchPad = new Sprite('launchPad',launchPadPainter),
ballPainter = {
ball_fill_style:'rgb(255,255,0)',
ball_stroke_style:'rgb(0,0,0,0.4)',
paint:function(ball,context){
context.save();
context.shadowColor = undefined;
context.lineWidth = 2;
context.fillStyle = this.ball_fill_style;
context.strokeStyle = this.ball_stroke_style;
context.beginPath();
context.arc(ball.left,ball.top,ball.radius,0,Math.PI*2,false);
context.clip();
context.fill();
context.stroke();
context.restore();
}
},
lob = {
lastTime:0,
gravity_force:9.81,
applyGravity:function(elapsed){
ball.velocityY = (this.gravity_force*elapsed) - (launchVelocity*Math.sin(launchAngle));
},
updateBallPosition:function(updateDelta){
ball.left += ball.velocityX*(updateDelta)*pixelsPerMeter;
ball.top += ball.velocityY*(updateDelta)*pixelsPerMeter;
},
checkForThreePointer:function(){
if(ball.top<0){
threePointer = true;
}
},
checkBallBounds:function(){
if(ball.top>canvas.height||ball.left>canvas.width){
console.log('超出边界了');
reset();
}
},
execute:function(ball,context,time){
var elapsedFrameTime;
var elapsedFlightTime;
if(ballInFlight){
elapsedFlightTime = (time - launchTime)/1000;
elapsedFrameTime = (time - this.lastTime)/1000;
this.applyGravity(elapsedFlightTime);
this.updateBallPosition(elapsedFrameTime);
this.checkForThreePointer();
this.checkBallBounds();
}
this.lastTime = time;
}
},
ball = new Sprite('ball',ballPainter,[lob]),
catchBall = {
ballInBucket:function(){
return ball.left > bucket.left+bucket.width/2&&
ball.left < bucket.left+bucket.width&&
ball.top > bucket.top&&
ball.top < bucket.top+bucket.height/3;
},
adjustScore:function(){
if(threePointer){
lastScore = 3;
}else{
lastScore = 2;
};
score += lastScore;
scoreBoard.innerText = score;
},
execute:function(bucket,context,time){
if(ballInFlight && this.ballInBucket()){
console.log('进球了');
reset();
this.adjustScore();
}
}
},
bucket = new Sprite('bucket',new ImagePainter('img/bucket.png'),[catchBall]);
function windowToCanvas(x,y){
var bbox = canvas.getBoundingClientRect();
return {
x: x- bbox.left*(canvas.width/bbox.width),
y: y - bbox.top*(canvas.height/bbox.height)
}
}
function reset(){
ball.left = launchPad_x+launch_width/2;
ball.top = launchPad_y - ball.height/2;
ball.velocityX = 0;
ball.velocityY = 0;
ballInFlight = false;
needInStructions = false;
lastScore = 0;
}
function showText(text){
var textWidth;
context.font = '42px Helvetica';
textWidth = context.measureText(text).width;
context.save();
context.shadowColor = undefined;
context.strokeStyle = 'rgb(80,120,210)';
context.fillStyle = 'rgba(100,140,230,0.5)';
context.fillText(text,canvas.width/2-textWidth/2,canvas.height/2);
context.strokeText(text,canvas.width/2-textWidth/2,canvas.height/2);
context.restore();
}
function drawGuidewire(){
context.moveTo(ball.left,ball.top);
context.lineTo(lastMouse.left,lastMouse.top);
context.stroke();
}
function updateBackgroundText(){
if(lastScore == 3){
showText('三分球');
}else if(lastScore == 2){
showText('两分球');
}else if(lastScore == 0||needInstructions ){
showText('点击发球');
}
}
function updateSprites(time){
bucket.update(context,time);
launchPad.update(context,time);
ball.update(context,time);
}
function paintSprites(){
bucket.paint(context);
launchPad.paint(context);
ball.paint(context);
}
ball.width = ball_radius*2;
ball.height = ball.width;
ball.left = launchPad_x+launch_width/2;
ball.top = launchPad_y - ball.height/2;
ball.radius = ball_radius;
context.lineWidth = 0.5;
context.strokeStyle = 'rgba(0,0,0,0.5)';
context.shadowColor = 'rgba(0,0,0,0.5)';
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;
bucket.left = bucket_x;
bucket.top = bucket_y;
bucket.width = bucket_width;
bucket.height = bucket_height;
window.requestAnimationFrame(animate);
function animate(time){
time = +new Date();
context.clearRect(0,0,canvas.width,canvas.height);
if(!ballInFlight){
console.log('还没点击');
drawGuidewire();
updateBackgroundText();
};
updateSprites(time);
paintSprites();
window.requestAnimationFrame(animate);
};
canvas.onmousemove = function(e){
var loc;
var deltaX;
var deltaY;
e.preventDefault();
if(!ballInFlight){
loc = windowToCanvas(e.clientX,e.clientY);
lastMouse.left = loc.x;
lastMouse.top = loc.y;
deltaX = Math.abs(lastMouse.left - ball.left);
deltaY = Math.abs(lastMouse.top - ball.top);
launchAngle = Math.atan(parseFloat(deltaY)/parseFloat(deltaX));
launchVelocity = 4*(deltaY/Math.sin(launchAngle))/pixelsPerMeter;
launchAngleOutput.innerText = (launchAngle*180/Math.PI).toFixed(2);
launchVelocityOutput.innerText = launchVelocity.toFixed(2);
}
}
canvas.onmousedown = function(e){
var loc;
e.preventDefault();
if(!ballInFlight){
console.log('点击小球抛掷中');
ball.velocityX = launchVelocity*Math.cos(launchAngle);
ball.velocityY = launchVelocity*Math.sin(launchAngle);
ballInFlight = true;
threePointer = false;
launchTime = +new Date();
}
}
</script>
</html>
