查看: 222|回复: 6
|
新科技,写App without Coding
[复制链接]
|
|
本帖最后由 隐居小镇 于 30-9-2025 02:50 PM 编辑
Google 几年前有新的 features,可以写custom App 出来,也可以分享给人用,叫作 AppSheet,分享方式
就像 Google docs 和 Google Sheet |
|
|
|
|
|
|
|
发表于 30-9-2025 02:31 PM
|
显示全部楼层
|
|
|
|
|
|
|
发表于 30-9-2025 02:42 PM
|
显示全部楼层
|
|
|
|
|
|
|

楼主 |
发表于 30-9-2025 02:48 PM
来自手机
|
显示全部楼层
开卷有益 发表于 30-9-2025 02:31 PM
听过opal吗?马来西亚用户现在能不能使用?
不懂 |
|
|
|
|
|
|
|
发表于 30-9-2025 02:50 PM
|
显示全部楼层
那天我做了一个棋盘类的金庸群侠传
|
|
|
|
|
|
|
|
发表于 30-9-2025 02:52 PM
|
显示全部楼层
以下是文件 HTML 打砖块游戏, 你可以试下
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>打砖块(HTML5 Canvas)</title>
<style>
html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial}
.wrap{min-height:100%;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:18px;background:linear-gradient(180deg,#0b1220,#10243a);color:#e6f7ff}
h1{margin:0 0 12px;font-size:20px}
#gameArea{background:#071827;border-radius:8px;padding:12px;box-shadow:0 6px 30px rgba(0,0,0,.5)}
canvas{display:block;background:#071827;border:2px solid rgba(255,255,255,0.04);border-radius:6px}
.controls{margin-top:10px;display:flex;gap:8px;align-items:center}
button{background:#1b8fbf;color:white;border:0;padding:8px 12px;border-radius:6px;cursor:pointer;font-weight:600}
button.secondary{background:#3a3f44}
.info{margin-left:12px;font-size:14px}
.overlay{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,0.6);padding:18px;border-radius:10px;text-align:center}
.status{margin-top:10px;font-size:14px}
</style>
</head>
<body>
<div class="wrap">
<h1>打砖块(按 ← → 控制挡板,A:切换自动)</h1>
<div id="gameArea">
<div style="position:relative;display:inline-block">
<canvas id="canvas" width="760" height="480"></canvas>
<div id="overlay" class="overlay" style="display:none"></div>
</div>
<div class="controls">
<button id="startBtn">开始 / 继续</button>
<button id="autoBtn">一键自动运行 (A)</button>
<button id="restartBtn" class="secondary">重新开始</button>
<div class="info">得分: <span id="score">0</span> | 生命: <span id="lives">3</span></div>
</div>
</div>
</div>
<script>
// 简洁版打砖块游戏 — 单文件
(function(){
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const autoBtn = document.getElementById('autoBtn');
const overlay = document.getElementById('overlay');
const scoreEl = document.getElementById('score');
const livesEl = document.getElementById('lives');
// 游戏参数
const W = canvas.width, H = canvas.height;
// 挡板
const paddle = {w:100,h:14,x W-100)/2,y:H-30, speed:7, dx:0};
// 小球
const ball = {r:8,x:W/2,y:H-60,vx:4,vy:-4, stuck:true};
// 砖块
const brick = {rows:5, cols:9, w:72, h:22, padding:8, offsetTop:40, offsetLeft:22};
let bricks = [];
let score = 0;
let totalBricks = 0;
let lives = 3;
let running = false;
let autoPlay = false; // 自动模式
let rafId = null;
function initBricks(){
bricks = [];
for(let r=0;r<brick.rows;r++){
bricks[r] = [];
for(let c=0;c<brick.cols;c++){
bricks[r][c] = {x:0,y:0,status:1};
totalBricks++;
}
}
}
function resetGame(){
score = 0; lives = 3; totalBricks = 0; initBricks();
paddle.x = (W-paddle.w)/2; paddle.dx = 0;
ball.x = W/2; ball.y = H-60; ball.vx = 4; ball.vy = -4; ball.stuck = true;
scoreEl.textContent = score; livesEl.textContent = lives;
overlay.style.display='none';
}
function drawPaddle(){
ctx.fillStyle = '#d2f1ff';
roundRect(ctx,paddle.x,paddle.y,paddle.w,paddle.h,6,true,false);
}
function drawBall(){
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2);
ctx.fillStyle = '#ffd27f';
ctx.fill();
ctx.closePath();
}
function drawBricks(){
for(let r=0;r<brick.rows;r++){
for(let c=0;c<brick.cols;c++){
const b = bricks[r][c];
if(b.status){
const bx = c*(brick.w+brick.padding)+brick.offsetLeft;
const by = r*(brick.h+brick.padding)+brick.offsetTop;
b.x = bx; b.y = by;
// 颜色按行微调
const hue = 190 - r*14;
ctx.fillStyle = `hsl(${hue} 70% 60%)`;
roundRect(ctx,bx,by,brick.w,brick.h,4,true,false);
}
}
}
}
function drawHUD(){
ctx.font = '14px system-ui, Arial';
ctx.fillStyle = 'rgba(230,247,255,0.9)';
ctx.fillText('得分: '+score,10,18);
ctx.fillText('生命: '+lives, W-80,18);
}
function update(){
// 移动挡板
if(paddle.dx !== 0){
paddle.x += paddle.dx;
if(paddle.x < 0) paddle.x = 0;
if(paddle.x + paddle.w > W) paddle.x = W - paddle.w;
}
// 自动模式:挡板追踪球
if(autoPlay){
const center = paddle.x + paddle.w/2;
if(Math.abs(center - ball.x) > 6){
paddle.x += (ball.x > center) ? paddle.speed : -paddle.speed;
if(paddle.x < 0) paddle.x = 0;
if(paddle.x + paddle.w > W) paddle.x = W - paddle.w;
}
}
// 小球
if(ball.stuck){
// 小球跟随挡板
ball.x = paddle.x + paddle.w/2;
ball.y = paddle.y - ball.r - 1;
} else {
ball.x += ball.vx; ball.y += ball.vy;
// 边界反弹
if(ball.x + ball.r > W){ ball.x = W - ball.r; ball.vx *= -1; }
if(ball.x - ball.r < 0){ ball.x = ball.r; ball.vx *= -1; }
if(ball.y - ball.r < 0){ ball.y = ball.r; ball.vy *= -1; }
// 挡板碰撞
if(ball.y + ball.r > paddle.y && ball.y + ball.r < paddle.y + paddle.h && ball.x > paddle.x && ball.x < paddle.x + paddle.w){
// 根据撞击点调整角度
const collidePoint = (ball.x - (paddle.x + paddle.w/2));
const normalized = collidePoint / (paddle.w/2);
const maxBounce = Math.PI/3; // 60° max
const angle = normalized * maxBounce;
const speed = Math.sqrt(ball.vx*ball.vx + ball.vy*ball.vy);
ball.vx = speed * Math.sin(angle);
ball.vy = -Math.abs(speed * Math.cos(angle));
ball.y = paddle.y - ball.r - 1;
}
// 砖块碰撞
for(let r=0;r<brick.rows;r++){
for(let c=0;c<brick.cols;c++){
const b = bricks[r][c];
if(!b.status) continue;
// 矩形-圆形碰撞近似
if(ball.x + ball.r > b.x && ball.x - ball.r < b.x + brick.w && ball.y + ball.r > b.y && ball.y - ball.r < b.y + brick.h){
// 破坏砖块
b.status = 0;
score += 10; totalBricks--;
scoreEl.textContent = score;
// 简单反弹:根据球心与砖中心判断方向
const brickCenterX = b.x + brick.w/2;
const brickCenterY = b.y + brick.h/2;
const dx = (ball.x - brickCenterX);
const dy = (ball.y - brickCenterY);
if(Math.abs(dx) > Math.abs(dy)) ball.vx *= -1; else ball.vy *= -1;
// 检查胜利
if(totalBricks <= 0){
showOverlay('你赢了!🎉');
running = false; ball.stuck = true;
}
// 跳出循环
r = brick.rows; break;
}
}
}
// 掉落底部
if(ball.y - ball.r > H){
lives--;
livesEl.textContent = lives;
if(lives <= 0){
showOverlay('游戏结束');
running = false; ball.stuck = true;
} else {
// 重置小球到挡板
ball.stuck = true; ball.vx = 4*(Math.random()>0.5?1:-1); ball.vy = -4;
}
}
}
}
function draw(){
ctx.clearRect(0,0,W,H);
drawBricks();
drawPaddle();
drawBall();
drawHUD();
}
function loop(){
update(); draw();
if(running) rafId = requestAnimationFrame(loop);
}
function startGame(){
if(!running){
running = true;
rafId = requestAnimationFrame(loop);
}
// 如果小球被卡在挡板上,松开就发射
if(ball.stuck){ ball.stuck = false; }
overlay.style.display='none';
}
function showOverlay(text){
overlay.innerHTML = '<div style="font-size:18px;font-weight:700">'+text+'</div>' +
'<div class="status" style="margin-top:8px">按开始继续,或按重新开始重置</div>';
overlay.style.display = 'block';
}
// 工具函数:带圆角矩形
function roundRect(ctx,x,y,w,h,r,fill,stroke){
if(typeof r === 'undefined') r=5;
ctx.beginPath();
ctx.moveTo(x+r,y);
ctx.arcTo(x+w,y,x+w,y+h,r);
ctx.arcTo(x+w,y+h,x,y+h,r);
ctx.arcTo(x,y+h,x,y,r);
ctx.arcTo(x,y,x+w,y,r);
ctx.closePath();
if(fill) ctx.fill();
if(stroke) ctx.stroke();
}
// 事件
document.addEventListener('keydown',(e)=>{
if(e.key === 'ArrowLeft'){ paddle.dx = -paddle.speed; }
if(e.key === 'ArrowRight'){ paddle.dx = paddle.speed; }
if(e.key === ' '){ // space 发射/发球
if(ball.stuck) { ball.stuck = false; startGame(); }
e.preventDefault();
}
if(e.key.toLowerCase() === 'a'){ // 切换自动模式
autoPlay = !autoPlay; autoBtn.textContent = autoPlay? '自动: 已开 (A)' : '一键自动运行 (A)';
}
});
document.addEventListener('keyup',(e)=>{
if(e.key === 'ArrowLeft' || e.key === 'ArrowRight'){ paddle.dx = 0; }
});
// 按钮
startBtn.addEventListener('click',()=>{ startGame(); });
autoBtn.addEventListener('click', ()=>{ autoPlay = !autoPlay; autoBtn.textContent = autoPlay? '自动: 已开 (A)' : '一键自动运行 (A)'; });
restartBtn.addEventListener('click', ()=>{ cancelAnimationFrame(rafId); running=false; resetGame(); startGame(); });
// 初始化并自动开始,满足用户“自动一键运行”的需求
resetGame(); // 初始化数据
// 页面加载后显示提示,等待开始
overlay.innerHTML = '<div style="font-size:18px;font-weight:700">按 ← → 控制挡板,空格发射球</div><div style="margin-top:8px">点击【开始 / 继续】或按空格开始。按 A 开/关自动。</div>';
overlay.style.display='block';
// 让画布在高 DPI 屏幕上更清晰
(function fixDPR(){
const dpr = window.devicePixelRatio || 1;
if(dpr !== 1){
canvas.width = W * dpr; canvas.height = H * dpr;
canvas.style.width = W + 'px'; canvas.style.height = H + 'px';
ctx.scale(dpr,dpr);
}
})();
})();
</script>
</body>
</html>
|
|
|
|
|
|
|
|
发表于 30-9-2025 06:08 PM
|
显示全部楼层
|
|
|
|
|
|
| |
本周最热论坛帖子
|